#include "texture.h"
#include "base.h"
#include "Renderer.h"
#include "Surface.h"
#include "Utils.h"

bool Texture::CreateFromILImage(uint imageName, Texture *pTexture)
{
	if(pTexture == NULL)
		return false;
	if(ilIsImage(imageName))
	{
		ilBindImage(imageName);
		ilConvertImage(IL_UNSIGNED_BYTE, IL_RGBA);
		int imgWidth = ilGetInteger(IL_IMAGE_WIDTH);
		int imgHeigth = ilGetInteger(IL_IMAGE_HEIGHT);
		int imgFormat = ilGetInteger(IL_IMAGE_FORMAT);
		pTexture->_LoadGlTextureFromPixels32((uint*)ilGetData(), imgWidth, imgHeigth);
		pTexture->m_bValidTexture = true;
		pTexture->m_nWidth = imgWidth;
		pTexture->m_nHeight = imgHeigth;
		*pTexture->m_validator = TEXTURE_OK;
		return true;
	}else{
		return false;
	}
}

Texture::Texture() : m_validator(new int())
{
	(*m_validator) = TEXTURE_ERR_NULL;
	m_nTextureName = 0;
	m_bValidTexture = false;
	m_nWidth = 0;
	m_nHeight = 0;
}
Texture::Texture(const Texture &tex)
{
	m_nTextureName = tex.m_nTextureName;
	m_nHeight = tex.m_nHeight;
	m_nWidth = tex.m_nWidth;
	m_bValidTexture = tex.m_bValidTexture;
	m_validator = tex.m_validator;
}
Texture Texture::operator=(const Texture &tex)
{
	return Texture(tex);
}
Texture::Texture(Surface *pSurface) : m_validator(new int())
{
	if(pSurface == NULL) {
		(*m_validator) = TEXTURE_ERR_NULL;
		return; 
	}
	_LoadGlTexture(pSurface);
}
void Texture::_LoadGlTexture(const std::string &filename)
{
	ILuint texName;
	ilGenImages(1, &texName);
	ilBindImage(texName);

	//Not using unicode
	//wstring wFilename = MakeUnicodeString(filename);
	const char *strImageLoad = filename.c_str();
	if(!ilLoadImage(strImageLoad))
	{
		ILenum error = ilGetError();
		const char *szErrorString = iluErrorString(error);
		RError(cout << "Image loading error while loading image: "
			<< filename << "; " << szErrorString);
		ilDeleteImages(1, &texName);
		(*m_validator) = TEXTURE_ERR_FILE;
		return;
	}

	//Resize to 32Bit RGBA / 4Byte
	ilConvertImage(IL_UNSIGNED_BYTE, IL_RGBA);

	m_nWidth = ilGetInteger(IL_IMAGE_WIDTH);
	m_nHeight = ilGetInteger(IL_IMAGE_HEIGHT);

	int nW = NextPowerof(m_nWidth);
	int nH = NextPowerof(m_nHeight);
	if((nW != m_nWidth) || (nH != m_nHeight))
	{
		//Resize image to matching size
		iluImageParameter(ILU_PLACEMENT, ILU_UPPER_LEFT);
		iluEnlargeCanvas(nW, nH, 1);
	}

	_LoadGlTextureFromPixels32((uint*)ilGetData(), nW, nH);

	ilDeleteImage(texName);
}
void Texture::_LoadGlTexture(Surface *pSurface)
{
	_LoadGlTextureFromPixels32(pSurface->GetSurface()->pixels, pSurface->Width(), pSurface->Heigth());
}
void Texture::_LoadGlTextureFromPixels32(void *pixels, uint width, uint height)
{
	glErrorCheck();

	uint tImg = ilGenImage();
	ilBindImage(tImg);
	ilTexImage(width, height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, pixels);

	m_nWidth = width;
	m_nHeight = height;

	int nW = NextPowerof(width);
	int nH = NextPowerof(height);
	if((nW != width) || (nH != height))
	{
		//Resize image to matching size
		iluImageParameter(ILU_PLACEMENT, ILU_UPPER_LEFT);
		iluEnlargeCanvas(nW, nH, 1);
		m_nWidth = nW;
		m_nHeight = nH;
	}

	//Create texture from surface
	glEnable(GL_TEXTURE_2D);
	glGenTextures(1, &m_nTextureName);
	glBindTexture(GL_TEXTURE_2D, m_nTextureName);

	//Create texture from pixel buffer
	glTexImage2D(GL_TEXTURE_2D, 0, 4, m_nWidth, m_nHeight, 0, GL_RGBA,
		GL_UNSIGNED_BYTE, ilGetData());

	if(glErrorCheck())
	{
		(*m_validator) = TEXTURE_ERR_GLINTERNAL;
		RError(cout << "Invalid texture load [" << m_nTextureName << "]");
		return;
	}

	//Delete temporary ilImage
	ilDeleteImage(tImg);
}
Texture::Texture(const std::string &filename) : m_validator(new int())
{
	_LoadGlTexture(filename.c_str());
}
Texture::~Texture()
{
	FreeTexture();
}
void Texture::FreeTexture()
{
	if((*m_validator) == TEXTURE_OK)
	{
		(*m_validator) = TEXTURE_ERR_UNLOADED;
		m_bValidTexture = false;
		m_nWidth = 0;
		m_nHeight = 0;

		//Finish openGl operations
		glFinish();
		glDeleteTextures(1, &m_nTextureName);
		m_nTextureName = 0;
	}
}
bool Texture::IsValidTexture()
{
	if((*m_validator) != TEXTURE_OK)
	{
		return false;
	}
	if(m_nWidth == 0 || m_nHeight == 0)
	{
		return false;
	}
	return true;
}
void Texture::BindTexture()
{
	glBindTexture(GL_TEXTURE_2D, m_nTextureName);
}

Rect Texture::GetTextureDimensionsRectangle()
{
	return Rect(0, 0, m_nWidth, m_nHeight);
}
vector2 Texture::GetTextureDimensionsVector()
{
	return vector2(m_nWidth, m_nHeight);
}
uint Texture::Width() { return m_nWidth; }
uint Texture::Heigth() { return m_nHeight; }
uint Texture::GetTextureName() const
{
	return m_nTextureName;
}